package com.ubxtech.cloud.balance;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.ubxtech.annotation.MsgTypeEnum;
import com.ubxtech.balance.dto.ServiceInstanceGreyDTO;
import com.ubxtech.balance.util.ServiceInstanceUtil;
import com.ubxtech.cloud.client.MsgWebsocketServiceIdClient;
import com.ubxtech.cloud.properties.CloudProperties;
import com.ubxtech.core.context.ContextUtil;
import com.ubxtech.core.context.Result;
import com.ubxtech.core.dto.MsgWebsocketServiceIdDTO;
import com.ubxtech.core.utils.GrayVersionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.*;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.core.env.Environment;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 定义灰度负载均衡策略
 *
 * @author madi
 */
@Slf4j
public class GrayRoundRobinLoadBalancer extends RoundRobinLoadBalancer {

	private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

	private String serviceId;
	private Environment environment;
	/** 用于轮训算法 */
	private AtomicInteger nextServerAtomic;
	private CloudProperties cloudProperties;
	/** 请求websocket获取对应的serviceId */
	private MsgWebsocketServiceIdClient msgWebsocketServiceIdClient;

	public GrayRoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId,Environment environment,CloudProperties cloudProperties,MsgWebsocketServiceIdClient msgWebsocketServiceIdClient) {
		super(serviceInstanceListSupplierProvider, serviceId);
		this.serviceId = serviceId;
		this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
		this.environment = environment;
		this.cloudProperties = cloudProperties;
		this.msgWebsocketServiceIdClient = msgWebsocketServiceIdClient;

		nextServerAtomic = new AtomicInteger(0);
	}


	@Override
	public Mono<Response<ServiceInstance>> choose(Request request) {
		ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
				.getIfAvailable(NoopServiceInstanceListSupplier::new);
		return supplier.get(request).next().map(serviceInstances -> getInstanceResponse(serviceInstances, request));
	}

	Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, Request request) {

		// 注册中心无可用实例 抛出异常
		if (CollUtil.isEmpty(instances)) {
			log.warn("No instance available {}", serviceId);
			return new EmptyResponse();
		}
		String reqVersion = ContextUtil.getGrayVersion();

		//分析出有版本号的实例
		ServiceInstanceGreyDTO serviceInstanceGreyDTO = ServiceInstanceUtil.analysisGreyInstance(instances, reqVersion);
		//匹配的实例
		List<ServiceInstance> instancesFilter = serviceInstanceGreyDTO.getInstancesFilter();
		//version为空或者为all的实例,目的是如果没有带版本号,其中有服务带了版本号,则不调用
		List<ServiceInstance> emptyVersionInstancesFilter = serviceInstanceGreyDTO.getEmptyVersionInstancesFilter();

		Object context = request.getContext();
		String msgPushServiceUrl = cloudProperties.getMsgPushServiceUrl();;
		//处理websocket的转发规则
		if(StrUtil.isNotBlank(msgPushServiceUrl) && context instanceof RequestDataContext){
			RequestDataContext requestDataContext = (RequestDataContext) context;
			String msgType = ContextUtil.get("msgType", String.class,"");
			String msgTopic = ContextUtil.get("msgTopic", String.class,"");

			//目前只能只能根据url来,消息类型,1:服务消息,2:websocket消息,3:短信,4:邮件
			if (msgPushServiceUrl != null
					&& requestDataContext.getClientRequest().getUrl().toString().contains(msgPushServiceUrl)  && String.valueOf(MsgTypeEnum.WEBSOCKET.getCode()).equals(msgType) && StrUtil.isNotBlank(msgTopic)
			) {
				//可以直接获取缓存中的映射关系拿到serviceId ,匹配目前的serviceInstance
				MsgWebsocketServiceIdDTO msgWebsocketServiceIdDTO = new MsgWebsocketServiceIdDTO();
				msgWebsocketServiceIdDTO.setTarget(msgTopic);
				Result<String>  result = msgWebsocketServiceIdClient.getServiceId(msgWebsocketServiceIdDTO);
				if (result != null && StrUtil.isNotBlank(result.getData()) && result.getCode() != null && result.getCode() == 200) {
					ServiceInstance serviceInstance = ServiceInstanceUtil.getInstanceByServiceId(instances, result.getData());
					if (serviceInstance != null) {
						return new DefaultResponse(serviceInstance);
					}
				}
			}
		}
		//优先匹配到的,没有匹配到再是没有配置版本的,然后再是所有
		ServiceInstance serviceInstance = GrayVersionUtil.getInstance(instancesFilter.size() == 0 ? (emptyVersionInstancesFilter.size() == 0 ? instances : emptyVersionInstancesFilter) : instancesFilter, environment.getProperty("ubxtech.cloud.balanceType"), nextServerAtomic);
		return new DefaultResponse(serviceInstance);
//		return super.choose(request).block();
	}
}